<template>
  <div class="tree">
    <div class="top-btns">
      <a-input v-model="searchValue" placeholder="搜索" />
      <a-button class="add" shape="round" @click="add(-1)">+</a-button>
    </div>

    <a-tree
      block-node
      :tree-data="treeData"
      :class="externClassName"
      :expandedKeys="expandedKeys"
      :selectedKeys="selectedKeys"
      :auto-expand-parent="true"
      :draggable="routerName !== 'translate'"
      :replaceFields="{ children: 'children', title: 'label', key: 'key' }"
      @expand="onExpand"
      @select="onSelect"
      @drop="onDrop"
      @dragenter="onDragEnter"
    >
      <template #title="record">
        <span :class="['title', { hightlight: highlightArr.includes(record.key) }]">
          <Ellipsis :length="30">{{ record.label }}</Ellipsis>
          <!-- <template v-if="routerName === 'translate'"> -->
          <!-- {{ record.label }} -->
          <!-- </template> -->
          <!-- <a-tooltip placement="topRight" v-else>
            <template slot="title">{{ record.label }}</template>
            {{ record.label }}
          </a-tooltip> -->
        </span>
        <a-dropdown :trigger="['click']">
          <a class="ant-dropdown-link" @click.stop>
            <a-button
              class="add_btn"
              shape="round"
              @click.stop="add(record)"
              v-if="record.type != lastLevelType && routerName !== 'translate'"
            >+</a-button
            >
            <a-button class="action_btn">···</a-button>
          </a>
          <template #overlay>
            <a-menu @click="(e) => onMenuClick(e, record)">
              <a-menu-item key="2">编辑{{ typeMap[record.type] }}</a-menu-item>
              <a-menu-item key="3">删除{{ typeMap[record.type] }}</a-menu-item>
            </a-menu>
          </template>
        </a-dropdown>
      </template>
    </a-tree>

    <NewProject ref="projectRef" @success="treeCUDSuccess" @close="modalClose" />
    <NewApp ref="appRef" @success="treeCUDSuccess" @close="modalClose" />
    <NewModule ref="moduleRef" @success="treeCUDSuccess" @close="modalClose" />
    <NewString ref="stringRef" @success="treeCUDSuccess" @close="modalClose" />
  </div>
</template>

<script>
import NewProject from '../project/createUpdate.vue'
import NewApp from '../application/createUpdate.vue'
import NewModule from '../module/createUpdate.vue'
import NewString from '../string/createUpdate.vue'
import { Ellipsis } from '@/components'

import { generator, generator_translate, projectDetails } from '@/utils/util'
import { deleteProject, stringTree, projectSort } from '@/api/project'
import { deleteApp, appSort } from '@/api/app'
import { deleteModule, moduleSort } from '@/api/module'
import { deleteString, stringSort } from '@/api/string'

export default {
  name: 'Tree',

  components: { NewProject, NewApp, NewModule, NewString, Ellipsis },

  props: {
    routerName: { type: String, default: () => 'string' },
    externClassName: { type: String, default: () => '' }
  },

  data () {
    return {
      treeData: [],
      selectProjectId: -1,
      editProjectId: -1,
      selectedKeys: [],
      dataList: [],
      expandedKeys: [],
      highlightArr: [],
      searchValue: '',
      typeMap: { 0: '项目', 1: '应用', 2: '模块', 3: '字符串' },
      // 最后层次的结点type，用于隐藏menu的菜单选项
      lastLevelType: 3,
      defaultLangObj: {}
    }
  },

  mounted () {
    this.getTreeData()
  },

  watch: {
    searchValue: { handler: 'change', immediate: true }
  },

  methods: {
    // 获取树状数据
    getTreeData () {
      this.treeData = []

      stringTree().then((res) => {
        if (res.code) {
          this.treeData = this.routerName === 'string' ? generator(res.data) : generator_translate(res.data)
          this.generateList(this.treeData)

          if (sessionStorage.getItem('newObj')) this.handlevirtualClick()
        }
      })
    },
    // 生成搜索列表数据（用于树关键字搜索的对象数组）
    generateList (data) {
      for (let i = 0; i < data.length; i++) {
        const node = data[i]
        const { label, key } = node
        this.dataList.push({ key, title: label })
        if (node.children) this.generateList(node.children)
      }
    },
    // 监听输入框数据变化
    change (newVal, oldVal) {
      if (!newVal) this.highlightArr.length = 0
      const tempArr = this.dataList.map((item) => {
        if (newVal && item.title.indexOf(newVal) > -1) {
          this.highlightArr.push(item.key)
          return this.getParentKey(item.key, this.treeData)
        }
        return null
      })
      const expanded = tempArr.filter((item, i, self) => item && self.indexOf(item) === i)
      this.expandedKeys = expanded
    },
    // 获取父级key值（需要根据后端返回的数据字段名更改 【value】字段）
    getParentKey (key, tree) {
      let parentKey
      for (let i = 0; i < tree.length; i++) {
        const node = tree[i]
        if (node.children) {
          if (node.children.some((item) => item.key === key)) {
            parentKey = node.key
          } else if (this.getParentKey(key, node.children)) parentKey = this.getParentKey(key, node.children)
        }
      }
      return parentKey
    },
    // 获取展开的树节点key数组
    getExpandKeys (key) {
      const p_1_key = this.getParentKey(key, this.treeData)
      const p_2_ey = this.getParentKey(p_1_key, this.treeData)
      const p_3_ey = this.getParentKey(p_2_ey, this.treeData)
      const expandedKeys = [p_3_ey, p_2_ey, p_1_key, key]
      return expandedKeys.filter((item) => !!item)
    },
    // 模拟选中树结点
    handlevirtualClick () {
      const newObj = JSON.parse(sessionStorage.getItem('newObj'))
      if (newObj) {
        const { project_id, app_id, module_id, string_id, project_name, app_name, module_name, string_name } = newObj
        let key, type, value

        if (project_name) {
          key = `project_${project_id}`
          type = 0
          value = project_id
        } else if (app_name) {
          key = `app_${app_id}`
          type = 1
          value = app_id
        } else if (module_name) {
          key = `module_${module_id}`
          type = 2
          value = module_id
        } else if (string_name) {
          key = `string_${string_id}`
          type = 3
          value = string_id
        }
        const obj = {
          selected: true,
          node: { dataRef: { projectId: project_id, appId: app_id, moduleId: module_id, type, value } }
        }
        this.onExpand(this.getExpandKeys(key))
        this.onSelect([key], obj)
        sessionStorage.removeItem('newObj')
      }
    },
    // 选择树结点方法
    onSelect (key, e) {
      if (!e.selected) return

      this.selectedKeys = key
      this.selectProjectId = e.node.dataRef.projectId

      this.$emit('selectSuccess', e.node.dataRef)

      this.onExpand(this.getExpandKeys(key[0]))
    },
    // 展开树
    onExpand (expandedKeys) {
      this.expandedKeys = expandedKeys
    },
    // 拖拽开始
    onDragEnter (info) {
      // expandedKeys 需要受控时设置
      this.expandedKeys = info.expandedKeys
    },
    // 拖拽排序
    onDrop (info) {
      const { dragNode, node: dropNode, dropPosition: infoDropPos, dropToGap } = info
      const { eventKey: dragKey, dataRef: dragData } = dragNode
      const { eventKey: dropKey, dataRef: dropData, pos: dropPosition } = dropNode
      const { type: dragType } = dragData
      const { type: dropType } = dropData

      const dropPos = dropPosition.split('-')
      const position = infoDropPos - Number(dropPos[dropPos.length - 1])

      if ((!dropToGap && dragType - 1 !== dropType) || (dropToGap && dragType !== dropType)) {
        this.$message.warning('拖拽后结点等级不符!')
        return
      }

      const loop = (data, key, callback) => {
        data.forEach((item, index, arr) => {
          if (item.key === key) {
            return callback(item, index, arr)
          }
          if (item.children) {
            return loop(item.children, key, callback)
          }
        })
      }
      const data = [...this.treeData]

      // Find dragObject
      let dragObj
      loop(data, dragKey, (item, index, arr) => {
        arr.splice(index, 1)
        dragObj = item
      })
      if (!dropToGap) {
        // Drop on the content
        loop(data, dropKey, (item) => {
          item.children = item.children || []
          /// where to insert 示例添加到头部，可以是随意位置
          item.children.push(dragObj)
        })
      } else if (
        (dropNode.children || []).length > 0 &&
        // Has children
        dropNode.expanded &&
        // Is expanded
        position === 1 // On the bottom gap
      ) {
        loop(data, dropKey, (item) => {
          item.children = item.children || []
          // where to insert 示例添加到头部，可以是随意位置
          item.children.unshift(dragObj)
        })
      } else {
        let ar = []
        let i = 0
        loop(data, dropKey, (item, index, arr) => {
          ar = arr
          i = index
        })
        position === -1 ? ar.splice(i, 0, dragObj) : ar.splice(i + 1, 0, dragObj)
      }
      this.treeData = data
      this.sortProcess(dragType, dragData, dropData)
    },
    // 拖拽排序处理
    sortProcess (dragType, dragData, dropData) {
      // this.editId = dragData.projectId
      const apiMap = { 0: projectSort, 1: appSort, 2: moduleSort, 3: stringSort }
      const { treeData } = this
      const { projectId: dropProjectId, appId: dropAppId, moduleId: dropModuleId } = dropData
      const { appId: dragAppId, moduleId: dragModuleId, value, label } = dragData
      const params = []

      switch (dragType) {
        case 0:
          treeData.forEach((item, index) => {
            params.push({ project_id: item.projectId, sort: index + 1 })
          })
          break
        case 1:
          treeData
            .find((item) => item.projectId === dropProjectId)
            .children.forEach((ite, index) => {
              params.push({ app_id: ite.appId, sort: index + 1 })
            })
          this.$refs.appRef.form = { project_id: dropProjectId, app_name: label, app_id: dragAppId }
          break
        case 2:
          treeData
            .find((item) => item.projectId === dropProjectId)
            .children.find((ite) => ite.appId === dropAppId)
            .children.forEach((it, index) => {
              params.push({ module_id: it.moduleId, sort: index + 1 })
            })
          this.$refs.moduleRef.form = {
            project_id: dropProjectId,
            app_id: dropAppId,
            module_name: label,
            module_id: dragModuleId
          }
          break
        case 3:
          treeData
            .find((item) => item.projectId === dropProjectId)
            .children.find((ite) => ite.appId === dropAppId)
            .children.find((it) => it.moduleId === dropModuleId)
            .children.forEach((i, index) => {
              params.push({ string_id: i.value, sort: index + 1 })
            })
          this.$refs.stringRef.form = {
            project_id: dropProjectId,
            app_id: dropAppId,
            module_id: dropModuleId,
            string_name: label,
            string_id: value
          }
          break
      }
      apiMap[dragType]({ data: params }).then((res) => {
        if (res.code === 200) {
          this.$message.success(res.msg)
          switch (dragType) {
            case 0:
              this.getTreeData()
              break
            case 1:
              this.$refs.appRef.updateApp(false)
              break
            case 2:
              this.$refs.moduleRef.updateModule(false)
              break
            case 3:
              this.$refs.stringRef.updateString(false)
              break
          }
        } else this.$message.error(res.msg)
      })
    },
    // 添加项目/应用/模块/字符串
    add (record) {
      const { type, value, projectId, appId } = record.dataRef || {}
      // this.editProjectId = projectId || -1
      switch (type) {
        default:
          this.$refs.projectRef.open()
          break
        case 0:
          this.$refs.appRef.open()
          this.$refs.appRef.form.project_id = value
          break
        case 1:
          this.$refs.moduleRef.open()
          this.$refs.moduleRef.form.project_id = projectId
          this.$refs.moduleRef.form.app_id = value
          break
        case 2:
          this.$refs.stringRef.open()
          this.$refs.stringRef.form.project_id = projectId
          this.$refs.stringRef.form.app_id = appId
          this.$refs.stringRef.form.module_id = value
          break
      }
    },
    // 菜单点击(编辑项目/应用/模块)
    onMenuClick (e, record) {
      console.log(record.dataRef)
      const { label, type, projectId: project_id, appId: app_id, moduleId: module_id, value: id } = record.dataRef
      this.editProjectId = project_id
      switch (type) {
        case 0:
          if (Number(e.key) === 2) {
            this.$refs.projectRef.open()
            this.$refs.projectRef.modalType = 1
            this.projectDetail(id)
          } else if (Number(e.key) === 3) {
            this.$confirm({
              title: '系统提示',
              content: '确定要删除吗',
              onOk: () => {
                deleteProject({ project_id: id }).then((res) => {
                  if (res.code === 200) {
                    this.$message.success(res.msg)
                    this.treeCUDSuccess({ type: 'delete' })
                  } else this.$message.error(res.msg)
                })
              }
            })
          }
          break
        case 1:
          if (Number(e.key) === 2) {
            this.$refs.appRef.open()
            this.$refs.appRef.modalType = 1
            this.$refs.appRef.form = { project_id, app_name: label, app_id: id }
          } else if (Number(e.key) === 3) {
            this.$confirm({
              title: '系统提示',
              content: '确定要删除吗',
              onOk: () => {
                deleteApp({ app_id: id }).then((res) => {
                  if (res.code === 200) {
                    this.$message.success(res.msg)
                    this.treeCUDSuccess({ type: 'delete' })
                  } else this.$message.error(res.msg)
                })
              }
            })
          }
          break
        case 2:
          if (Number(e.key) === 2) {
            this.$refs.moduleRef.open()
            this.$refs.moduleRef.modalType = 1
            this.$refs.moduleRef.form = { project_id, app_id, module_name: label, module_id: id }
          } else if (Number(e.key) === 3) {
            this.$confirm({
              title: '系统提示',
              content: '确定要删除吗',
              onOk: () => {
                deleteModule({ module_id: id }).then((res) => {
                  if (res.code === 200) {
                    this.$message.success(res.msg)
                    this.treeCUDSuccess({ type: 'delete' })
                  } else this.$message.error(res.msg)
                })
              }
            })
          }
          break
        case 3:
          if (Number(e.key) === 2) {
            this.$refs.stringRef.open()
            this.$refs.stringRef.modalType = 1
            this.$refs.stringRef.form = { project_id, app_id, module_id, string_name: label, string_id: id }
          } else if (Number(e.key) === 3) {
            this.$confirm({
              title: '系统提示',
              content: '确定要删除吗',
              onOk: () => {
                deleteString({ string_id: id }).then((res) => {
                  if (res.code === 200) {
                    this.$message.success(res.msg)
                    this.treeCUDSuccess({ type: 'delete' })
                  } else this.$message.error(res.msg)
                })
              }
            })
          }
          break
      }
    },
    // 编辑项目
    projectDetail (project_id) {
      projectDetails(project_id).then((res) => {
        const { checkedArr, defaultLanguage, form } = res
        this.$refs.projectRef.checkedArr = checkedArr
        this.$refs.projectRef.defaultLanguage = defaultLanguage
        this.$refs.projectRef.form = form
      })
    },
    // 新增/编辑/删除成功
    treeCUDSuccess (e) {
      // console.log(e)
      const res = { selectId: e?.project_id || this.selectProjectId, editId: this.editProjectId }
      if (e.type !== 'delete') sessionStorage.setItem('newObj', JSON.stringify(e))

      Object.assign(res, e)
      this.$emit('treeCUDSuccess', res)
    },
    // 弹窗关闭
    modalClose () {
      this.editProjectId = -1
    }
  }
}
</script>

<style lang="less" scoped>
.tree {
  width: 100%;
  height: 100%;

  .top-btns {
    height: 32px;
    display: flex;
    align-items: center;
    margin-bottom: 10px;

    .add {
      padding: 0;
      margin: 0 10px;
      box-sizing: border-box;
      display: flex;
      align-items: center;
      justify-content: center;
      color: rgba(0, 0, 0, 0.35);

      :deep(span) {
        width: 30px;
        height: 32px;
        font-weight: bold;
        display: flex;
        align-items: center;
        justify-content: center;
      }
    }
  }

  // .string_tree :deep(.ant-tree-node-content-wrapper) {
  //   width: calc(100% - 48px) !important;
  // }

  :deep(.ant-tree-node-content-wrapper) {
    width: calc(100% - 72px) !important;
    padding: 0;
    border: 0;

    .ant-tree-title {
      width: 100%;
      height: 100%;
      display: inline-block;

      .title {
        width: 100%;
        height: 24px;
        line-height: 24px;
        display: inline-block;
        position: relative;

        &.hightlight {
          border: 1px dashed;
        }

        span {
          width: 100%;
          overflow: hidden;
          white-space: nowrap;
          text-overflow: ellipsis;
          display: inline-block;
        }
      }
    }

    a.ant-dropdown-link.ant-dropdown-trigger {
      width: 48px;
      height: 24px;
      text-align: center;
      font-size: 20px;
      position: absolute;
      right: 0;
      color: rgba(0, 0, 0, 0.25);
      text-align: right;
      display: inline-flex;

      .ant-btn {
        width: 24px;
        height: 24px;
        padding: 0;
        box-shadow: unset;

        &.action_btn {
          border: unset;

          span {
            width: 24px;
            height: 24px;
            font-size: 20px;
            line-height: 24px;
          }
        }
      }
    }
  }

  .trans_tree :deep(.ant-tree-node-content-wrapper) {
    width: calc(100% - 48px) !important;

    a.ant-dropdown-link.ant-dropdown-trigger {
      width: 24px;
    }
  }
}

.add_btn,
.action_btn {
  padding: 0;
  width: 24px;
  height: 24px;
}
</style>
